package com.gitee.kamismile.stoneEureka.server.service.imp;

import com.gitee.kamismile.stone.commmon.util.JsonUtil;
import com.gitee.kamismile.stone.commmon.util.ValueUtils;
import com.gitee.kamismile.stoneEureka.client.EurekaClientConstant;
import com.gitee.kamismile.stoneEureka.pojo.FilterDefinition;
import com.gitee.kamismile.stoneEureka.pojo.PredicateDefinition;
import com.gitee.kamismile.stoneEureka.pojo.RouteDefinition;
import com.gitee.kamismile.stoneEureka.server.GatewayConstant;
import com.google.gson.reflect.TypeToken;
import com.gitee.kamismile.stoneEureka.server.service.IEurekaService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class EurekaVersionService implements IEurekaService {

    String cmd = "app@register@version";

    @Autowired
    GatewayConstant gatewayConstant;

    @Autowired
    private StringRedisTemplate redisTemplate;

    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public Map<String, Object> doService(Map<String, Object> data) {
        RouteDefinition definition = new RouteDefinition();
        definition.setId(ValueUtils.isStringNull(data.get("token")));
        definition.setAppEnable(ValueUtils.isStringNull(data.get("appEnable")));
        PredicateDefinition predicate = new PredicateDefinition();
        Map<String, String> predicateParams = new HashMap<>(16);
        predicate.setName("Path");
        predicateParams.put("pattern", ValueUtils.isStringNull(data.get("appPath")));
        predicateParams.put("pathPattern", ValueUtils.isStringNull(data.get("appPath")));
        predicateParams.put("appName", ValueUtils.isStringNull(data.get("appName")));
        predicate.setArgs(predicateParams);

        Map<String, String> headerPredicateParams = new HashMap<>(16);
        headerPredicateParams.put("header", "versionInfo");
        headerPredicateParams.put("regexp", ValueUtils.isStringNull(data.get("appVersion")));
        PredicateDefinition headerPredicate = new PredicateDefinition();
        headerPredicate.setName("Header");
        headerPredicate.setArgs(headerPredicateParams);

        definition.setPredicates(Arrays.asList(predicate, headerPredicate));

        URI uri = UriComponentsBuilder.fromUriString(ValueUtils.isStringNull(data.get("appServer"))).build().toUri();
        definition.setUri(uri);

        processPredicates(data, definition);
        processFilters(data, definition);

        redisTemplate.opsForHash().put(gatewayConstant.getGatewayRoutes(), data.get("token"), JsonUtil.toJson(definition));
        redisTemplate.convertAndSend(gatewayConstant.getGatewayRouteNotify(), gatewayConstant.getGatewayRouteNotify());
        return new HashMap<>();
    }

    private void processPredicates(Map<String, Object> data, RouteDefinition definition) {
        String appPredicateDefinition = ValueUtils.isStringNull(data.get("appPredicates"));
        if (StringUtils.isBlank(appPredicateDefinition)) {
            return;
        }
        List<EurekaClientConstant.AppPredicateDefinition> appPredicateDefinitions = JsonUtil.fromJson(appPredicateDefinition, new TypeToken<List<EurekaClientConstant.AppPredicateDefinition>>() {
        }.getType());

        List<PredicateDefinition> predicateDefinitions = appPredicateDefinitions.stream().map(v -> {
            PredicateDefinition predicateDefinition = new PredicateDefinition();
            predicateDefinition.setName(v.getName());
            predicateDefinition.setArgs(v.getArgs());
            return predicateDefinition;
        }).collect(Collectors.toList());
        List<PredicateDefinition> list = definition.getPredicates();
        if (!CollectionUtils.isEmpty(list)) {
            predicateDefinitions.addAll(list);
        }
        definition.setPredicates(predicateDefinitions);
    }

    private void processFilters(Map<String, Object> data, RouteDefinition definition) {
        String appFilterDefinition = ValueUtils.isStringNull(data.get("appFilters"));
        if (StringUtils.isBlank(appFilterDefinition)) {
            return;
        }
        List<EurekaClientConstant.AppFilterDefinition> appFilterDefinitions = JsonUtil.fromJson(appFilterDefinition, new TypeToken<List<EurekaClientConstant.AppFilterDefinition>>() {
        }.getType());

        List<FilterDefinition> filterDefinitions = appFilterDefinitions.stream().map(v -> {
            FilterDefinition filterDefinition = new FilterDefinition();
            filterDefinition.setName(v.getName());
            filterDefinition.setArgs(v.getArgs());
            return filterDefinition;
        }).collect(Collectors.toList());
        definition.setFilters(filterDefinitions);
    }


    @Override
    public void delete(String routeId) {
        if (redisTemplate.opsForHash().hasKey(gatewayConstant.getGatewayRoutes(), routeId)) {
            redisTemplate.opsForHash().delete(gatewayConstant.getGatewayRoutes(), routeId);
            redisTemplate.convertAndSend(gatewayConstant.getGatewayRouteNotify(), gatewayConstant.getGatewayRouteNotify());
        }
    }

    @Override
    public boolean isCmd(String cmd) {
        return this.cmd.equals(cmd);
    }
}
